//------------------------------------------------------------------------------
// <copyright file="WinsockStringSocket.h" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
#ifndef GAMESTEST_WINSOCK_STRING_SOCKET
#define GAMESTEST_WINSOCK_STRING_SOCKET
#if _MSC_VER > 1000
#pragma once
#endif

#include "IRpcStringSocket.h"

#include <winsock2.h>
#include <ppltasks.h>

namespace Microsoft { namespace Internal { namespace GamesTest { namespace Rpc { namespace Server { namespace Ut {
    class WinsockStringSocketTests;
}}}}}}

namespace Microsoft { namespace Internal { namespace GamesTest { namespace Rpc { namespace Server {

    class WinsockStringSocket : public IRpcStringSocket
    {
    private:
        SOCKET m_socket;

        HANDLE m_workerThread;

        concurrency::critical_section s_synchronizationContext;
        bool m_receiving;
        concurrency::task<void> m_dataReceivedCallbackTask;
        bool m_dataReceivedTaskInitialized;

        DataReceivedCallback m_dataReceivedCallback;
        SocketDisconnectedCallback m_clientDisconnectedCallback;

    public:
        WinsockStringSocket(SOCKET socket);
        virtual ~WinsockStringSocket(void);

        HRESULT StartListening(DataReceivedCallback dataReceivedCallback, SocketDisconnectedCallback clientDisconnectedCallback);		

        GAMESTEST_ANNOTATE_HRESULT_METHOD HRESULT SendData(const std::wstring& data);

        virtual std::wstring GetIpAddress();

    private:
        friend class Microsoft::Internal::GamesTest::Rpc::Server::Ut::WinsockStringSocketTests;

        WinsockStringSocket(const WinsockStringSocket&) {}
        WinsockStringSocket& operator=(WinsockStringSocket&) {}

        HRESULT SendDataLengthInBytes(int dataLength);
        int DataLengthInBytesSendImpl(char* buffer, int length);

        HRESULT SendDataContent(char* buffer, int bufferLength);
        int DataContentSendImpl(char* buffer, int length);

        bool Read7BitEncodedInt(int & i);	
        bool ReadByte(BYTE & byte);
        int ReadByteRecvImpl(char* buffer, int strLength);

        bool ReadString(int length);
        int ReadStringRecvImpl(char* buffer, int strLength);

        int Write7BitEncodedInt(char buffer[4], int value);

        void CloseSocket();
        void Shutdown();

        DWORD Process();

        static DWORD ThreadStart(LPVOID instance);

        static void RaiseSocketDisconnectedEvent(SocketDisconnectedCallback callback, WinsockStringSocket * socket);
        void WaitForDataReceivedCallbackTasks();
    };

}}}}}

#endif